package com.chinamsp.exception;

import java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;

import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * 断言基础服务提供者
 * @author shifenghu
 *
 */
public class AssertProvider {
	
	/**
	 * 检查 对象是否不为空
	 * @param obj 要检查的对象
	 * @param exception 
	 * @return 当前对象
	 */
	public AssertProvider isNotNull(Object obj, BaseException exception) {
		messageAndClass(exception);
		if (obj == null) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查对象是否为空
	 * @param obj
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider isNull(Object obj, BaseException exception) {
		messageAndClass(exception);
		if (obj != null) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查 字符串 是否不为空
	 * <p>
	 * 		"" 和 null 均表示空
	 * </p>
	 * @param source
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider isNotBlank(String source, BaseException exception) {
		messageAndClass(exception);
		// 如果 source == ""、" "或者null，都表示检查失败
		if (StringUtils.isEmpty(source)) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查  source 是否否和摸个正则 
	 * @param source 要检查的数据，如果不是 string ，会自动调用 .toString ，请保证 source 不能为null
	 * @param regex
	 * @param exception
	 * @return
	 */
	public AssertProvider isRegex(Object source, String regex, BaseException exception) {
		messageAndClass(exception);
		isNotNull(source, exception);
		String value = source.toString();
		// 检查 是否符合此 正则
		if ( !Pattern.matches(regex, value)){
			throw exception;
		}
		return this;
	}
	
	
	/**
	 * 检查 字符串 是否不为空
	 * <p>
	 * 		"" 、" " 和 null 均表示空
	 * </p>
	 * @param source
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider isNotEmpty(String source, BaseException exception) {
		messageAndClass(exception);;
		// 如果 source == ""、" "或者null，都表示检查失败
		if (StringUtils.isEmpty(source) || source.trim().length() == 0) {
			throw exception;
		}
		return this;
	}
	
	
	/**
	 * 检查result是否为true
	 * @param result
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider isTrue(boolean result, BaseException exception) {
		messageAndClass(exception);;
		if (!result) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查 result 是否为false
	 * @param result
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider isFalse(boolean result, BaseException exception) {
		messageAndClass(exception);;
		if (result) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查 集合是否为空 list=null||list.isEmpty()
	 * @param list
	 * @param exception
	 * @return 当前对象
	 */
	public <T> AssertProvider isNotEmpty(Collection<T> list, BaseException exception) {
		messageAndClass(exception);;
		if (CollectionUtils.isEmpty(list)) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查 数组是否为空 array=null||array.length==0
	 * @param array
	 * @param exception
	 * @return 当前对象
	 */
	public <T> AssertProvider isNotEmpty(T[] array, BaseException exception) {
		messageAndClass(exception);;
		if (array == null || array.length == 0) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查 map 是否为空， map==null||map.isEmpty()
	 * @param list
	 * @param exception
	 * @return 当前对象
	 */
	public <K,V> AssertProvider isNotEmpty(Map<K,V> map, BaseException exception) {
		messageAndClass(exception);;
		if (CollectionUtils.isEmpty(map)) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查 对象的类型
	 * @param type 检查的类型
	 * @param target 要检查的对象
	 * @param exception
	 * @return 当前对象
	 */
	public <T> AssertProvider isAssignable(Class<T> type, Object target, BaseException exception) {
		isNotNull(target, exception);
		isNotNull(type, exception);
		if(!type.isAssignableFrom(target.getClass())){
            throw exception;
        }
		return this;
	}
	
	/**
	 * 检查 字符串长度
	 * <p>
	 * 		该方法会对参数先进行非null检查， 如果为null，不管 min 和 max 设置多少，都认为是成功，所以如果要检查的数据不允许为空，则请先调用{@link #isNotEmpty(String, String, String, Class)}。
	 * </p>
	 * @param source 
	 * @param min 最小长度，<=0 表示不限制
	 * @param max 最大长度，<=0 表示不限制
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider length(String source, int min, int max, BaseException exception) {
		messageAndClass(exception);;
		// 如果字符串为空，则忽略下面的检查
		if (source == null) {
			return this;
		}
		// 最小值检查
		if (min > 0 && min > source.length()) {
			throw exception;
		}
		// 最大值检查
		if (max > 0 && max < source.length()) {
			throw exception;
		}
		return this;
	}
	
	/**
	 * 检查字符串长度
	 * <p>
	 * 		该方法会对参数先进行非null检查， 如果为null，不管 min 设置多少，都认为是成功，所以如果要检查的数据不允许为空，则请先调用{@link #isNotEmpty(String, BaseException)}。
	 * </p>
	 * @param source
	 * @param min
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider min(String source, int min, BaseException exception) {
		return length(source, min, 0, exception);
	}
	
	/**
	 * 检查字符串长度
	 * <p>
	 * 		该方法会对参数先进行非null检查， 如果为null，不管 max 设置多少，都认为是成功，所以如果要检查的数据不允许为空，则请先调用{@link #isNotEmpty(String, BaseException)}。
	 * </p>
	 * @param source
	 * @param max
	 * @param exception
	 * @return 当前对象
	 */
	public AssertProvider max(String source, int max, BaseException exception) {
		return length(source, 0, max, exception);
	}
	
	/**
	 * 检查是否包含
	 * <p>
	 * 		该方法会先检查集合是否为空，然后检查 value 是否为空，最后再使用 equales 方法比较是否相等
	 * </p>
	 * @param list
	 * @param value
	 * @param exception
	 * @return 当前对象
	 */
	public <T> AssertProvider isContains(Collection<T> list, T value, BaseException exception) {
		messageAndClass(exception);;
		isNotEmpty(list, exception);
		isNotNull(value, exception);
		for (T t : list) {
			if (value.equals(t)) {
				return this;
			}
		}
		throw exception;
	}
	
	/**
	 * 检查是否包含
	 * <p>
	 * 		该方法会先检查数组是否为空，然后检查 value 是否为空，最后再使用 equales 方法比较是否相等
	 * </p>
	 * @param array
	 * @param value
	 * @param exception
	 * @return 当前对象
	 */
	public <T> AssertProvider isContains(T[] array, T value, BaseException exception) {
		messageAndClass(exception);;
		isNotEmpty(array, exception);
		isNotNull(value, exception);
		for (T t : array) {
			if (value.equals(t)) {
				return this;
			}
		}
		throw exception;
	}
	
	/**
	 * 检查基础数据
	 * @param code
	 * @param message
	 * @param clazz
	 */
	protected void messageAndClass(BaseException exception) {
		Assert.notNull(exception, "检查的 exception 不能为空");
	}
	
	/**
	 * 数字类型正则
	 */
	public static final String REGEX_DIGIT = "^\\d+$";
	
	/**
	 * 字母正则
	 */
	public static final String REGEX_LETTER = "^[A-Za-z]+$";
	
	/**
	 * 支持小数的数字
	 */
	public static final String REGEX_NUMBER = "^[\\d.]+$";
}